import { useRef, useState } from 'react'
import { useDebounceFn } from 'ahooks'
import { GetProp, message, Modal, Spin, theme, Upload, UploadFile } from 'antd'

import { useAntdPopupAnimation } from '@/services/popupSlot'
import { apiFileUpload } from '@oBiz/apis'
import { apiCheckWaybillExists, apiSaveWaybillFiles } from '../../apis'
import { accept, getProcessedFileList, getUploadTrigger, handleMsg, localValidate } from './utils'

/** 上传POD附件 */
export const UploadPODFilesModal = ({ destroy, onSuccess }: { destroy: () => void; onSuccess?: () => void }) => {
  const { token } = theme.useToken()
  const { open, onHide, afterOpenChange } = useAntdPopupAnimation(destroy)

  const [loading, setLoading] = useState(false)
  const [fileList, setFileList] = useState<UploadFile[]>([])
  const hasSucceededRef = useRef(false)

  // 使用防抖集中到一次  PS:直接操作RcFile对象
  const { run: debounceBeforeUpload } = useDebounceFn(
    async (pickFileList: Parameters<GetProp<typeof Upload, 'beforeUpload'>>[1]) => {
      // pickFileList 加工
      const processedFileList = getProcessedFileList(pickFileList)

      // 本地校验
      const errMsg = localValidate(processedFileList)
      if (errMsg) {
        message.error(errMsg)
        return
      }

      try {
        setLoading(true)
        // 远程校验
        const { resultMap } = await apiCheckWaybillExists(processedFileList.map(d => d.name))
        // 上传附件
        const promiseList: Promise<null | { fileUrl: string; fileName: string }>[] = []
        processedFileList.forEach(({ file, name }) => {
          if (resultMap[name]) {
            promiseList.push(
              apiFileUpload({ file, attachType: 1 }, true).catch(err => {
                console.error(err)
                const target = file as unknown as UploadFile // 直接操作file对象
                target.status = 'error'
                target.error = new Error('上传失败')
                return null
              }),
            )
          } else {
            const target = file as unknown as UploadFile // 直接操作file对象
            target.status = 'error'
            target.error = new Error('运单号不存在')
            promiseList.push(Promise.resolve(null))
          }
        })
        const resultList = await Promise.all(promiseList)
        const saveData: Parameters<typeof apiSaveWaybillFiles>[0] = []
        resultList.forEach((item, index) => {
          if (item) {
            saveData.push({
              waybillNo: processedFileList[index].name,
              fileUrl: item.fileUrl,
              fileName: item.fileName,
              fileType: 5,
            })
          }
        })
        // 保存
        if (saveData.length) {
          await apiSaveWaybillFiles(saveData)
          hasSucceededRef.current = true
        }
        // message反馈
        handleMsg(processedFileList)
        // 更新到列表
        setFileList(([...files]) => {
          processedFileList.forEach(({ file }) => {
            const repeatIndex = files.findIndex(f => f.name === file.name)
            if (repeatIndex > -1) {
              files.splice(repeatIndex, 1) // 同名覆盖
            }
            files.push(file)
          })
          return files
        })
      } finally {
        setLoading(false)
      }
    },
    { wait: 10 },
  )

  return (
    <Modal
      title="上传POD附件"
      width={600}
      open={open}
      onCancel={() => {
        onHide()
        if (hasSucceededRef.current) onSuccess?.()
      }}
      afterOpenChange={afterOpenChange}
      cancelText="关闭"
      footer={(_originNode, { CancelBtn }) => <CancelBtn />}
    >
      <div style={{ marginBottom: 12, color: token.colorTextSecondary }}>
        规则：批量上传POD，POD以运单号命名，批量上传后通过运单号进行识别，运单号识别成功则上传，请注意附件命名。
      </div>
      <Spin spinning={loading}>
        <Upload.Dragger
          multiple
          accept={accept}
          fileList={fileList}
          beforeUpload={(_, list) => {
            debounceBeforeUpload(list)
            return false
          }}
          showUploadList={{
            showRemoveIcon: file => file.status === 'error',
          }}
          onRemove={({ name, status }) => {
            if (status === 'error') setFileList(prev => prev.filter(f => f.name !== name))
          }}
        >
          {getUploadTrigger()}
        </Upload.Dragger>
      </Spin>
    </Modal>
  )
}
